#include "JMainWindow.h"

#include "JLog.h"
#include "JLogWidget.h"

#include "JProject.h"
#include "JProjectView.h"
#include "JProjectWizard.h"

#include "JScriptConsole.h"
#include "JScriptEditor.h"

#include "qttreepropertybrowser.h"

#include "JGLWidget.h"
#include "J3DModel.h"
#include "STLModel.h"
#include "JTSData.h"

#include "JAboutDialog.h"

#include <QSettings>
#include <QCloseEvent>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>


JMainWindow::JMainWindow(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags),
	m_nMovieWidth(640),
	m_nMovieHeight(480),
	m_nFrameRate(30),
	m_bPPToggle(false),
	m_nModelIndex(0)
{
	// generated from .ui file
	ui.setupUi(this);
	
	// recent project list
	for (int i = 0; i < MaxRecentProjects; ++i) {
		mRecentProjectActs[i] = new QAction(this);
		mRecentProjectActs[i]->setVisible(false);
		connect(mRecentProjectActs[i], SIGNAL(triggered()),this, SLOT(openRecent()));
		ui.menuRecent->addAction(mRecentProjectActs[i]);
	}
	updateRecentProjectActions();

	// link menu buttons to their corresponding functions
	createActionLinks();

	// the log widget
	JLogWidget *mLogWidget = new JLogWidget(ui.LogDockContents);
	ui.LogGridLayout->addWidget(mLogWidget,0,0);
	Log.Post("JointMD Launched");

	// the opengl window
	m_pGLWidget = new JGLWidget(ui.centerWidget, m_nMovieWidth, m_nMovieHeight);
	ui.centerWidgetLayout->addWidget(m_pGLWidget);

	// the project browser
	m_pProjectView = new JProjectView(ui.ProjectDockContents, ui.action3D_Model, ui.actionKinematics, NULL);
	ui.ProjectGridLayout->addWidget(m_pProjectView);

	// the scripting console
	m_pConsole = new JScriptConsole(ui.ScriptDockContents, PythonQt::self()->getMainModule());
	ui.ScriptGridLayout->addWidget(m_pConsole,1,0);

	// the property browser
	m_pPropertyBrowser = new QtTreePropertyBrowser(ui.PropertiesDockContents);
	ui.PropertiesGridLayout->addWidget(m_pPropertyBrowser);

	//JProjectWizard wiz(this);
	//wiz.exec();

	JScriptEditor *_editor = new JScriptEditor(m_pConsole);
	_editor->show();

	PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "Log", &Log);
	PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "Project", &Project);
	PythonQt::self()->addObject(PythonQt::self()->getMainModule(), "Canvas", m_pGLWidget);

	// reload previous window dimensions
	readWindowSetting();
	// the default untitled project
	newProject();
}

JMainWindow::~JMainWindow()
{

}

void JMainWindow::closeEvent( QCloseEvent *event )
{
	if (saveModified()) {
		writeWindowSettings();
		event->accept();
	} else {
		event->ignore();
	}
}

void JMainWindow::readWindowSetting()
{
	QSettings settings;
	// MainWindow geometry
	settings.beginGroup("JMainWindow");
	restoreGeometry(settings.value("Geometry").toByteArray());
	restoreState(settings.value("WindowState").toByteArray());
	settings.endGroup();
}

void JMainWindow::writeWindowSettings()
{
	QSettings settings;
	// MainWindow geometry
	settings.beginGroup("JMainWindow");
	settings.setValue("Geometry", saveGeometry());
	settings.setValue("WindowState", saveState());
	settings.endGroup();
}

void JMainWindow::createActionLinks()
{
	connect(ui.actionNew_Project, SIGNAL(triggered()), this, SLOT(newProject()));
	connect(ui.actionOpen, SIGNAL(triggered()), this, SLOT(open()));
	connect(ui.actionSave, SIGNAL(triggered()), this, SLOT(save()));
	connect(ui.actionSave_As, SIGNAL(triggered()), this, SLOT(saveAs()));
	connect(ui.actionQuit, SIGNAL(triggered()), this, SLOT(close()));
	connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(about()));
	connect(ui.actionHelp, SIGNAL(triggered()), this, SLOT(contents()));
	connect(ui.actionShortcuts, SIGNAL(triggered()), this, SLOT(shortcuts()));
	connect(ui.action3D_Model, SIGNAL(triggered()), this, SLOT(add3DModel()));
	connect(ui.actionKinematics, SIGNAL(triggered()), this, SLOT(addKinematics()));
	connect(ui.actionSnapshot, SIGNAL(triggered()), this, SLOT(takeSnapshot()));
	connect(ui.actionPlay, SIGNAL(triggered()), this, SLOT(playAnimation()));
	connect(ui.actionStop, SIGNAL(triggered()), this, SLOT(stopRecordingAnimation()));
	connect(ui.actionRecord, SIGNAL(triggered()), this, SLOT(recordAnimationToMovie()));
}

bool JMainWindow::saveModified()
{
	// warn if modified
	if (false) {
		QMessageBox::StandardButton ret;
		ret = QMessageBox::warning(this, tr("JointMD"),
			tr("This Project has been modified.\n"
			"Do you want to save your changes?"),
			QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
		if (ret == QMessageBox::Save)
			return save();
		else if (ret == QMessageBox::Cancel)
			return false;
	}
	return true;
}

void JMainWindow::updateRecentProjectActions()
{
	QSettings settings;
	QStringList files = settings.value("RecentProjectList").toStringList();

	int numRecentFiles = qMin(files.size(), (int)MaxRecentProjects);

	for (int i = 0; i < numRecentFiles; ++i) {
		QString text = tr("&%1 %2").arg(i + 1).arg(shortFilename(files[i]));
		mRecentProjectActs[i]->setText(text);
		mRecentProjectActs[i]->setData(files[i]);
		mRecentProjectActs[i]->setVisible(true);
	}
	for (int j = numRecentFiles; j < MaxRecentProjects; ++j)
		mRecentProjectActs[j]->setVisible(false);
}

void JMainWindow::loadProject(const QString &fileName)
{
	QFile file(fileName);
	if (!file.open(QFile::ReadOnly | QFile::Text)) {
		QMessageBox::warning(this, tr("JointMD"),
			tr("Cannot load project %1:\n%2.")
			.arg(fileName)
			.arg(file.errorString()));
		return;
	}
	QApplication::setOverrideCursor(Qt::WaitCursor);

	//PROJECT.setName(fileName);
	setCurrentProject(fileName);
	// project load code here
	//m_pGLWidget->setStateFileName(fileName);
	//m_pGLWidget->restoreStateFromFile();
	m_pGLWidget->restoreFromFile(fileName);
	//m_pProjectWidget->restoreFromFile(fileName);
	//m_pProjectWidget->read(&file);
	//m_projectView->openProject();
	
	QApplication::restoreOverrideCursor();
	
	//
	statusBar()->showMessage(tr("Project loaded"), 3000);
}

bool JMainWindow::saveProject(const QString &fileName)
{
	QFile file(fileName);
	if (!file.open(QFile::WriteOnly | QFile::Text)) {
		QMessageBox::warning(this, tr("Application"),
			tr("Cannot write project file %1:\n%2.")
			.arg(fileName)
			.arg(file.errorString()));
		return false;
	}
	QApplication::setOverrideCursor(Qt::WaitCursor);

	//PROJECT.setName(fileName);
	setCurrentProject(fileName);

	//save project file code here
	//m_pGLWidget->setStateFileName(fileName);
	//m_pGLWidget->saveStateToFile();
	//m_pProjectWidget->saveToFile(fileName);
	//m_pProjectWidget->write(&file);

	m_pGLWidget->saveToFile(fileName); // must be last
	
	QApplication::restoreOverrideCursor();
	
	//
	statusBar()->showMessage(tr("Project saved"), 3000);
	return true;
}

void JMainWindow::setCurrentProject(const QString &fileName)
{
	m_currentProjectName = fileName;
	//Project.Load(m_currentProjectName);

	//if (m_currentProjectName.isEmpty())
		//m_pProjectView->insertChild("Untitled");
	//else
		//m_pProjectView->insertChild(strippedName(m_currentProjectName));

	//set project modified as false
	//setWindowModified(false);
	//if (!m_currentProjectName.isEmpty())
	//	emit emitName(strippedName(fileName));

	if (!m_currentProjectName.isEmpty())
	{
	QSettings settings;
		QStringList files = settings.value("RecentProjectList").toStringList();
		files.removeAll(fileName);
		files.prepend(fileName);
		while (files.size() > MaxRecentProjects)
			files.removeLast();
	
		settings.setValue("RecentProjectList", files);
	
		foreach (QWidget *widget, QApplication::topLevelWidgets()) {
			JMainWindow *mainWin = qobject_cast<JMainWindow *>(widget);
			if (mainWin)
				mainWin->updateRecentProjectActions();
		}
	}

	QString shownName = m_currentProjectName;
	if (m_currentProjectName.isEmpty()) 
		shownName = "Untitled.jmd";
	setWindowFilePath(shownName);
	setWindowTitle( tr("%1[*] - %2" ).arg(shortFilename(shownName)).arg(tr("JointMD")) );
}

QString JMainWindow::shortFilename(const QString &fullFileName)
{
	return QFileInfo(fullFileName).fileName();
}

QString JMainWindow::strippedName(const QString &fullFileName)
{
	QString name = shortFilename(fullFileName);
	name.chop(4);
	return name;
}

// SLOTS for Actions

void JMainWindow::newProject()
{
	if (saveModified()) {
		// untitled project
		//PROJECT.setName("");
		setCurrentProject("");
	}
}

void JMainWindow::open()
{
	if (saveModified()) {
		QString fileName = QFileDialog::getOpenFileName(this,
			tr("Select a JointMD project to load"),
			QDir::currentPath(),
			tr("JointMD Project(*.jmd)") );
		if (!fileName.isEmpty())
			loadProject(fileName);
	}
}

bool JMainWindow::save()
{
	if (m_currentProjectName.isEmpty()) {
		return saveAs();
	} else {
		return saveProject(m_currentProjectName);
	}
}

bool JMainWindow::saveAs()
{
	QString fileName = QFileDialog::getSaveFileName(this,
		tr("Save As"), m_currentProjectName);
	if (fileName.isEmpty())
		return false;
	if (!fileName.contains(".jmd"))
		fileName += tr(".jmd");
	return saveProject(fileName);
}

void JMainWindow::about()
{
	JAboutDialog dialog(this);
	dialog.exec();
}

void JMainWindow::openRecent()
{
	QAction *action = qobject_cast<QAction *>(sender());
	if (action) loadProject(action->data().toString());
}

void JMainWindow::contents()
{

}

void JMainWindow::shortcuts()
{
	m_pGLWidget->help();
}

void JMainWindow::add3DModel()
{
	QString filePath = QFileDialog::getOpenFileName(this, 
		tr("Select a 3D STL Model File to Load"),
		m_currentProjectName, tr("STL files (*.stl)"));

	if (filePath.isEmpty())
		return;
		//m_pGLWidget->loadSTL(filePath);

	// this currently handles the jts file too
	m_pModelList[m_nModelIndex] = new J3DModel(m_pGLWidget, filePath);
	m_nModelIndex++;

	Project.Add3DModel(filePath);

	//m_pModel = new J3DModel(m_pGLWidget, filePath);
	//m_pModel = new JSTLModel(m_pGLWidget, filePath);
	//m_pProjectView->insertChild(strippedName(filePath));
}

void JMainWindow::addKinematics()
{
	QString filePath = QFileDialog::getOpenFileName(this, 
		tr("Select a JointTrack kinematics file to load"),
		m_currentProjectName, tr("JTS files (*.jts)"));

	if (filePath.isEmpty())
		return;
		//m_pGLWidget->loadJTS(filePath);

	JTSData m_data(filePath);
	m_data.display();

	Project.AddKinematics(filePath);

	//m_pProjectView->insertChild(strippedName(filePath));
}

void JMainWindow::takeSnapshot()
{
	if (!m_pGLWidget->openSnapshotFormatDialog())
		return;

	m_pGLWidget->setSnapshotQuality(98);

	QString format = m_pGLWidget->snapshotFormat();

	QString filename = QFileDialog::getSaveFileName(this,
		tr("Choose a filename for the snapshot"),m_currentProjectName,
		tr(format.toAscii()+tr(" (*").toAscii()+format.toLower().toAscii()+tr(")").toAscii()));

	if (filename.isEmpty())
		return;

	if (!filename.contains(tr(".")+format.toLower()))
		filename += tr(".")+format.toLower();

	m_pGLWidget->saveSnapshot(filename);
}

void JMainWindow::insertKeyframe()
{
	
}

void JMainWindow::removeKeyframe()
{

}

void JMainWindow::playAnimation()
{
	if (m_bPPToggle)
	{
		m_bPPToggle = false;
		for (int i = 0; i < m_nModelIndex; i++)
		{
			m_pModelList[i]->pause();
		}
		//m_pModel->pause();
	}
	else
	{
		m_bPPToggle = true;
		for (int i = 0; i < m_nModelIndex; i++)
		{
			m_pModelList[i]->play();
		}
	}
}

void JMainWindow::recordAnimationToMovie()
{
	/*QString filename = QFileDialog::getSaveFileName(this,
		tr("Choose a filename for the snapshot"),m_currentProjectName,
		tr("AVI file (*.avi)"));

	if (!filename.contains(tr(".avi")))
		filename += tr(".avi");

	if (!filename.isEmpty()){
		LOG.Post("Movie recording started");
		m_pGLWidget->beginRecordingMovie(filename);
	}*/

	m_pGLWidget->beginRecordingMovie();

	/*QDialog dialog(this);
	JGLVideoWidget video(&dialog);
	QGridLayout gridlayout(&dialog);
	gridlayout.setContentsMargins(0,0,0,0);
	gridlayout.setHorizontalSpacing(0);
	gridlayout.setVerticalSpacing(0);
	gridlayout.addWidget(&video);
	dialog.resize(m_movieWidth, m_movieHeight);
	dialog.exec();*/

}

void JMainWindow::stopRecordingAnimation()
{
	m_pGLWidget->stopRecordingMovie();

	for (int i = 0; i < m_nModelIndex; i++)
	{
		m_pModelList[i]->stop();
	}
	//m_pModel->stop();
}

void JMainWindow::loopAnimation()
{
	//m_pModel->loop();
	for (int i = 0; i < m_nModelIndex; i++)
	{
		m_pModelList[i]->loop();
	}
}